#include <sys/socket.h>  
#include <sys/epoll.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <fcntl.h>  
#include <unistd.h>  
#include <stdio.h>  
#include <errno.h>  
#include <iostream>  
#include <string.h>
using namespace std;
#define MAX_EVENTS 5000  
struct myevent_s
{
	int fd;
	void(*call_back)(int fd, int events, void *arg);
	int events;
	void *arg;
	int status; // 1: in epoll wait list, 0 not in  
	char buff[128]; // recv data buffer  
	int len, s_offset;
	long last_active; // last active time  
};
// set event
//设置事件	参数：对象 sokect 回调函数 参数
void EventSet(myevent_s *ev, int fd, void(*call_back)(int, int, void*), void *arg)
{
	ev->fd = fd;
	ev->call_back = call_back;
	ev->events = 0;
	ev->arg = arg;
	ev->status = 0;
	bzero(ev->buff, sizeof(ev->buff));
	ev->s_offset = 0;
	ev->len = 0;
	ev->last_active = time(NULL);
}
// add/mod an event to epoll  
//从 epoll 添加/移除 一个事件
void EventAdd(int epollFd, int events, myevent_s *ev)
{
	struct epoll_event epv = { 0, {0} };
	int op;
	epv.data.ptr = ev;
	epv.events = ev->events = events;
	//当在epoll等待队列中就是移除 不在就是添加
	if (ev->status == 1) {
		op = EPOLL_CTL_MOD;
	}
	else {
		op = EPOLL_CTL_ADD;
		ev->status = 1;
	}
	if (epoll_ctl(epollFd, op, ev->fd, &epv) < 0)
		printf("Event Add failed[fd=%d], evnets[%d]\n", ev->fd, events);
	//else
	//	printf("Event Add OK[fd=%d], op=%d, evnets[%0X]\n", ev->fd, op, events);
}
// delete an event from epoll  
//从epoll中删除一个事件	将清理出epoll等待队列
void EventDel(int epollFd, myevent_s *ev)
{
	struct epoll_event epv = { 0, {0} };
	if (ev->status != 1)
		return;
	epv.data.ptr = ev;
	ev->status = 0;
	epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd, &epv);
}
int g_epollFd;
myevent_s g_Events[MAX_EVENTS + 1]; // g_Events[MAX_EVENTS] is used by listen fd  
void RecvData(int fd, int events, void *arg);
void SendData(int fd, int events, void *arg);
// accept new connections from clients  
//从客户端中接受新连接
void AcceptConn(int fd, int events, void *arg)
{
	struct sockaddr_in sin;
	socklen_t len = sizeof(struct sockaddr_in);
	int nfd, i;
	// accept  
	if ((nfd = accept(fd, (struct sockaddr*)&sin, &len)) == -1)
	{
		if (errno != EAGAIN && errno != EINTR)
		{
		}
		//printf("%s: accept, %d", __func__, errno);
		return;
	}
	do
	{
		//获取队列非等待元素
		for (i = 0; i < MAX_EVENTS; i++)
		{
			if (g_Events[i].status == 0)
			{
				break;
			}
		}
		//达到最大上限
		if (i == MAX_EVENTS)
		{
			printf("%s:max connection limit[%d].", __func__, MAX_EVENTS);
			break;
		}
		// set nonblocking
		//将套接字设置为非阻塞
		int iret = 0;
		if ((iret = fcntl(nfd, F_SETFL, O_NONBLOCK)) < 0)
		{
			printf("%s: fcntl nonblocking failed:%d", __func__, iret);
			break;
		}
		// add a read event for receive data  
		//给获取的数据添加一个读事件
		EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]);
		EventAdd(g_epollFd, EPOLLIN, &g_Events[i]);
	} while (0);
	//printf("new conn[%s:%d][time:%d], pos[%d]\n", inet_ntoa(sin.sin_addr),
		//ntohs(sin.sin_port), g_Events[i].last_active, i);
}
// receive data  
//获取数据
void RecvData(int fd, int events, void *arg)
{
	struct myevent_s *ev = (struct myevent_s*)arg;
	int len;
	// receive data
	//recv参数 sokect buffer buffer长度 额外设置
	len = recv(fd, ev->buff + ev->len, sizeof(ev->buff) - 1 - ev->len, 0);
	//删除事件
	EventDel(g_epollFd, ev);
	if (len > 0)
	{
		ev->len += len;
		ev->buff[len] = '\0';
		//printf("C[%d]:%s\n", fd, ev->buff);
		// change to send event  
		//改变事件类型为发送事件
		EventSet(ev, fd, SendData, ev);
		EventAdd(g_epollFd, EPOLLOUT, ev);
	}
	else if (len == 0)
	{
		close(ev->fd);
		printf("[fd=%d] pos[%d], closed gracefully.\n", fd, ev - g_Events);
	}
	else
	{
		close(ev->fd);
		printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));
	}
}
// send data  
//发送数据
void SendData(int fd, int events, void *arg)
{
	struct myevent_s *ev = (struct myevent_s*)arg;
	int len;
	// send data  
	len = send(fd, ev->buff + ev->s_offset, ev->len - ev->s_offset, 0);
	if (len > 0)
	{
		//printf("send[fd=%d], [%d<->%d]%s\n", fd, len, ev->len, ev->buff);
		ev->s_offset += len;
		//发送完成
		if (ev->s_offset == ev->len)
		{
			// change to receive event
			EventDel(g_epollFd, ev);
			EventSet(ev, fd, RecvData, ev);
			EventAdd(g_epollFd, EPOLLIN, ev);
		}
	}
	else
	{
		//发送失败
		close(ev->fd);
		EventDel(g_epollFd, ev);
		printf("send[fd=%d] error[%d]\n", fd, errno);
	}
}
void InitListenSocket(int epollFd, short port)
{
	int listenFd = socket(AF_INET, SOCK_STREAM, 0);
	fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking  设置非阻塞模式
	//printf("server listen fd=%d\n", listenFd);
	//最大序号的一个事件给予监听套接字使用
	EventSet(&g_Events[MAX_EVENTS], listenFd, AcceptConn, &g_Events[MAX_EVENTS]);
	// add listen socket  
	EventAdd(epollFd, EPOLLIN, &g_Events[MAX_EVENTS]);
	// bind & listen  
	sockaddr_in sin;
	bzero(&sin, sizeof(sin));
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;
	sin.sin_port = htons(port);
	bind(listenFd, (const sockaddr*)&sin, sizeof(sin));
	listen(listenFd, 5);
}
int main(int argc, char **argv)
{
	unsigned short port = 8080; // default port  默认端口
	// create epoll  
	//创建一个epoll
	g_epollFd = epoll_create(MAX_EVENTS);
	if (g_epollFd <= 0)
		printf("create epoll failed.%d\n", g_epollFd);
	// create & bind listen socket, and add to epoll, set non-blocking  
	//创建且绑定监听sokect 而且添加到epoll中 设置为非阻塞模式
	InitListenSocket(g_epollFd, port);
	// event loop  
	//事件循环
	struct epoll_event events[MAX_EVENTS];
	//printf("server running:port[%d]\n", port);
	int checkPos = 0;
	while (1) {
		// a simple timeout check here, every time 100, better to use a mini-heap, and add timer event  
		//这里一个简单的超时检测，每次100轮回，比使用最小堆要好，而且添加时间事件
		long now = time(NULL);
		for (int i = 0; i < 100; i++, checkPos++) // doesn't check listen fd  不检测监听套接字
		{
			if (checkPos == MAX_EVENTS)
				checkPos = 0; // recycle  重置
			if (g_Events[checkPos].status != 1) 
				continue;	//事件不在等待队列
			long duration = now - g_Events[checkPos].last_active;	//客户端最近活跃时间
			if (duration >= 60) // 60s timeout  60s超时 断开连接
			{
				close(g_Events[checkPos].fd);
				printf("[fd=%d] timeout[%d--%d].\n", g_Events[checkPos].fd, g_Events[checkPos].last_active, now);
				EventDel(g_epollFd, &g_Events[checkPos]);
			}
		}
		// wait for events to happen  
		//等待事件发生
		//参数epoll	事件队列	最大事件数量	超时时间	返回值：触发事件数量
		int fds = epoll_wait(g_epollFd, events, MAX_EVENTS, 1000);
		if (fds < 0) {
			printf("epoll_wait error, exit\n");
			break;
		}
		for (int i = 0; i < fds; i++) {
			myevent_s *ev = (struct myevent_s*)events[i].data.ptr;
			if ((events[i].events&EPOLLIN) && (ev->events&EPOLLIN)) // read event  
			{
				ev->call_back(ev->fd, events[i].events, ev->arg);
			}
			if ((events[i].events&EPOLLOUT) && (ev->events&EPOLLOUT)) // write event  
			{
				ev->call_back(ev->fd, events[i].events, ev->arg);
			}
		}
	}
	// free resource  
	return 0;
}

